﻿using Base.Common;
using Base.Common.entity;
using Base.Common.httpServer;
using Base.Common.Mongon;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using WebApi;
using static httpApi.HttpApiFacade;

namespace httpApi {
    public class HttpServer {
        private TcpListener _listeners;
        private volatile bool _isInit;
        public HttpServer(int port) {
            var localEp = new IPEndPoint(IPAddress.Any ,port);
            try {
                _listeners = new TcpListener(IPAddress.Any ,port);
                _listeners.Start(5000);
                _isInit = true;
                _listeners.BeginAcceptTcpClient(AcceptAsync_Async ,null);
            } catch {
                Dispose();
            }
        }
        private void AcceptAsync_Async(IAsyncResult iar) {
            _listeners.BeginAcceptTcpClient(AcceptAsync_Async ,null);
            var client = _listeners.EndAcceptTcpClient(iar);
            BufferedStream _inputStream = new BufferedStream(client.GetStream());
            StreamWriter OutputStream = new StreamWriter(new BufferedStream(client.GetStream()) ,Encoding.UTF8);
            try {
                Processer p = new Processer();

                BaseResult res = p.Process(_inputStream,client,OutputStream);
                String value = JsonConvert.SerializeObject(res);
                if( res.code != 0 ) {
                    log(client.Client.RemoteEndPoint.ToString() ,p.HttpUrl ,JsonConvert.SerializeObject(p.param) ,value);
                }
                
                WriteSuccess(OutputStream ,value);

            } catch( Exception e ) {
               

            } finally {
                try {
                    OutputStream.Flush();
                } catch { }
                try {
                    _inputStream.Dispose();
                } catch { }
                try {
                    OutputStream.Dispose();
                } catch { }
                try {
                    client.Close();
                } catch { }
                _inputStream = null;
                OutputStream = null; // bs = null;            
            }
        }

        void log(String ip ,String url ,String param ,String value) {

            if( BaseConfig.httpServerLog ) {

                HttpServerLog log = new HttpServerLog();
                log.ip = ip;
                log.url = url;
                log.urlName = url;
                log.param = param;
                log.result = value;
                log.user = CookieHelper.LoginName();
                MGHttpServerLog.save(log);
            }
        }
        public void WriteSuccess(StreamWriter OutputStream ,String value) {
            OutputStream.WriteLine("HTTP/1.0 200 OK");
            OutputStream.WriteLine("Content-Type: application/json");
            OutputStream.WriteLine("Connection: close");
            OutputStream.WriteLine("Access-Control-Allow-Origin: *");
            OutputStream.WriteLine("Access-Control-Allow-Headers: Content-Type,token");
            OutputStream.WriteLine("Access-Control-Allow-Credentials: true");
            OutputStream.WriteLine("Access-Control-Allow-Methods: GET,POST,OPTIONS");
            OutputStream.WriteLine("Cache-Control:no-cache");
            OutputStream.WriteLine("Server:gk 17.01");
            OutputStream.WriteLine("");
            OutputStream.WriteLine(value);
        }
        public void Dispose() {
            if( _isInit ) {
                _isInit = false;
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }
        protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1) {
            if( flag1 ) {
                if( _listeners != null ) {
                    try {
                        _listeners.Stop();
                        _listeners = null;
                    } catch {
                    }
                }
            }
        }


        

        

    }

    public class Processer {

        public string HttpUrl;
        public Dictionary<String ,object> param;


        internal BaseResult Process(  Stream _inputStream,TcpClient client,StreamWriter OutputStream) {

            BaseResult res = new BaseResult();
            var request = Utils.ReadLine(_inputStream);


            var tokens = request.Split(' ');
            if( tokens.Length != 3 ) {
                res.code = 501;
                res.data = "invalid http request line";
                return res;
            }

            string HttpMethod = tokens[0].ToUpper();
            HttpUrl = tokens[1];

            if( HttpMethod == "OPTIONS" ) {
                res.code = 0;
                res.data = "";
                return res;
            }
            // Console.WriteLine(httpUrl);

            MyConsole.addMessage(HttpUrl);
            String[] uri = HttpUrl.Split('?');
            HttpParam newparam = null;
            try {
                newparam = HttpApiFacade.getAction(uri[0]);
                if( newparam == null ) {
                    res.code = 502;
                    res.data = " path error" + HttpUrl;
                    return res;
                }
            } catch( Exception e ) {
                LoggerCommon.error(HttpUrl ,e);
                res.code = 504;
                res.data = e.Message + "aciton 异常";
                return res;
            }

            try {
                param = newparam.mc;
                if( uri.Length > 1 ) {
                    Utils.getData(uri[1] ,param);
                }

                Hashtable ht = Utils.ParseRequest(_inputStream);


                if( HttpMethod.Equals("POST") ) {

                    String data = Utils.PostRequestExec(ht ,_inputStream);
                    ParameterInfo[] info = newparam.meth.parameterInfos;
                    ParameterInfo bodyInfo = newparam.meth.body;
                    if( bodyInfo != null ) {
                        Type bBodyType = bodyInfo.ParameterType;
                        object body = JsonConvert.DeserializeObject(data ,bBodyType);
                        param.Add(bodyInfo.Name.ToString() ,body);
                    }

                }
                return ( BaseResult ) newparam.doAction();
            } catch( Exception e ) {
                LoggerCommon.error(HttpUrl ,e);
                res.code = 503;
                res.data = e.Message;
                return res;
            }
        }


    }
}